﻿using Games.Common;
using System.Collections.Generic;
using System.Linq;

namespace Games.HuaRongDao
{
    class Game
    {
        private static string[] names = new string[] { "曹操", "张飞", "赵云", "马超", "黄忠", "关羽", "甲", "乙", "丙", "丁" };
        private const int TOP = 0b0000_0000_0000_0000_1111;
        private const int LEFT = 0b0001_0001_0001_0001_0001;
        private const int BOTTOM = 0b1111_0000_0000_0000_0000;
        private const int RIGHT = 0b1000_1000_1000_1000_1000;
        private const int DOOR = 0b0110_0000_0000_0000_0000;
        private int status;
        public int MinStep { get; set; }
        public List<Block> Blocks { get; set; } = new List<Block>();
        public void Init((long, int) mapdata)
        {
            this.status = 0;
            this.Blocks.Clear();
            var mask = 31;
            var ds = mapdata.Item1;
            MinStep = mapdata.Item2;
            for(int i = 0; i < names.Length; i++)
            {
                var name = names[i];
                var loc = ds & mask;
                ds >>= 5;
                var x = loc % 4;
                var y = loc / 4;
                var isv = ds & 1;
                ds >>= 1;
                int w = 1, h = 2;
                var pid = i;
                //if(pid != 0 && pid != 5)
                //{
                //    pid = 1;
                //}
                if(isv != 1)
                {
                    if(i == 0)
                    {
                        w = 2;
                    }
                    else if(i > 5)
                    {
                        h = 1;
                        pid = i+4;
                    }
                    else
                    {
                        w = 2;
                        h = 1;
                        if(i != 5)
                        {
                            pid = i + 5;
                        }
                    }
                }

                var block = new Block(i, (int)x, (int)y, w, h, pid, name);
                this.status |= block.GetStatus();
                this.Blocks.Add(block);
            }
        }
        public void Move(Block block, Direction direction, int step)
        {
            if(IsFinished() || step < 1)
            {
                return;
            }
            var origin = block.GetStatus();
            var statusWithOutCurrent = this.status ^ origin;
            if(direction == Direction.Down)
            {
                for(int i = 0; i < step; i++)
                {
                    if((origin & BOTTOM) != 0)
                    {
                        return;
                    }
                    origin <<= 4;
                    if((origin & statusWithOutCurrent) > 0)
                    {
                        return;
                    }
                    this.status = statusWithOutCurrent | origin;
                    block.Y++;
                }
            }
            else if(direction == Direction.Up)
            {
                for(int i = 0; i < step; i++)
                {
                    if((origin & TOP) != 0)
                    {
                        return;
                    }
                    origin >>= 4;
                    if((origin & statusWithOutCurrent) > 0)
                    {
                        return;
                    }
                    this.status = statusWithOutCurrent | origin;
                    block.Y--;
                }
            }
            else if(direction == Direction.Left)
            {
                for(int i = 0; i < step; i++)
                {
                    if((origin & LEFT) != 0)
                    {
                        return;
                    }
                    origin >>= 1;
                    if((origin & statusWithOutCurrent) > 0)
                    {
                        return;
                    }
                    this.status = statusWithOutCurrent | origin;
                    block.X--;
                }
            }
            else if(direction == Direction.Right)
            {
                for(int i = 0; i < step; i++)
                {
                    if((origin & RIGHT) != 0)
                    {
                        return;
                    }
                    origin <<= 1;
                    if((origin & statusWithOutCurrent) > 0)
                    {
                        return;
                    }
                    this.status = statusWithOutCurrent | origin;
                    block.X++;
                }
            }
        }

        public (int, int) GetRange(Block block, bool horizontal)
        {
            var origin = block.GetStatus();
            var statusWithOutCurrent = this.status ^ origin;
            if(horizontal)
            {
                var min = block.X;
                var max = block.X;
                for(int i = block.X - 1; i >= 0; i--)
                {
                    origin >>= 1;
                    if((statusWithOutCurrent & origin) == 0)
                    {
                        min = i;
                    }
                    else
                    {
                        break;
                    }
                }
                origin = block.GetStatus();
                for(int i = block.X + 1; i <= 4 - block.Width; i++)
                {
                    origin <<= 1;
                    if((statusWithOutCurrent & origin) == 0)
                    {
                        max = i;
                    }
                    else
                    {
                        break;
                    }
                }
                return (min, max);
            }
            else
            {
                var min = block.Y;
                var max = block.Y;
                for(int i = block.Y - 1; i >= 0; i--)
                {
                    origin >>= 4;
                    if((statusWithOutCurrent & origin) == 0)
                    {
                        min = i;
                    }
                    else
                    {
                        break;
                    }
                }
                origin = block.GetStatus();
                for(int i = block.Y + 1; i <= 5 - block.Height; i++)
                {
                    origin <<= 4;
                    if((statusWithOutCurrent & origin) == 0)
                    {
                        max = i;
                    }
                    else
                    {
                        break;
                    }
                }
                if(block.ID == 0 && max == 4 - block.Height)
                {
                    max += 1;
                }
                return (min, max);
            }
        }

        public bool IsFinished()
        {
            return (Blocks.FirstOrDefault(x => x.ID == 0).GetStatus() & DOOR) == DOOR;
        }
    }
}
